package com.youzi.tunnel.server.manager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.alibaba.fastjson.JSONObject;
import com.youzi.tunnel.common.utils.SystemUtils;
import com.youzi.tunnel.server.entity.Client;
import com.youzi.tunnel.server.entity.Tunnel;
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class TunnelManager {


    //隧道关系表在内存的映射<tunnelId:Tunnel>
    private static final Map<String, Tunnel> tunnelMap = new ConcurrentHashMap<>();


    static {
        String envPath = SystemUtils.getEnvPath();
        StringBuilder content = new StringBuilder();

        //首先读取当前执行jar文件同目录下的config_tunnel.json, 失败则去类路径读取
        try (Stream<String> stream = Files.lines(Paths.get(envPath + "/config_tunnel.json"), StandardCharsets.UTF_8)) {
            stream.forEach(content::append);
        } catch (IOException e) {
            log.info("读取当前执行jar文件同目录下的config_tunnel.json出现异常, 将读取类路径resource/config_tunnel.json!");
            InputStream is = ClientManager.class.getClassLoader().getResourceAsStream("config_tunnel.json");
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                String line;
                while ((line = br.readLine()) != null) {
                    content.append(line);
                }
            } catch (IOException unsupportedEncodingException) {
                log.error("读取必要必要配置异常, 系统退出!");
                System.exit(2);
            }
        }

        List<Tunnel> tunnels = JSONObject.parseArray(content.toString(), Tunnel.class);
        tunnels.forEach(e -> {
            tunnelMap.put(e.getId(), e);
        });
    }

    public static boolean isTunnelOnline(String tunnelId) {
        return tunnelMap.get(tunnelId).isAlive();
    }


    /**
     * 获取隧道
     *
     * @param tunnelId
     */
    public static Tunnel getTunnel(String tunnelId) {
        return tunnelMap.get(tunnelId);
    }

    /**
     * 获取隧道
     *
     * @param
     */
    public static Collection<Tunnel> getByFromClient(String clientId) {
        Collection<Tunnel> tunnels = tunnelMap.values();
        return tunnels.stream().filter(tunnel -> tunnel.getFromClient().equals(clientId)).collect(Collectors.toList());
    }

    /**
     * 获取客户端关联隧道
     *
     * @param
     */
    public static Collection<Tunnel> getRelevantTunnelByClient(String clientId) {
        Collection<Tunnel> tunnels = tunnelMap.values();
        return tunnels.stream().filter(tunnel -> tunnel.getToClient().equals(clientId) || tunnel.getFromClient().equals(clientId)).collect(Collectors.toList());
    }

    /**
     * 获取隧道
     *
     * @param
     */
    public static Collection<Tunnel> getByToClient(String clientId) {
        Collection<Tunnel> tunnels = tunnelMap.values();
        return tunnels.stream().filter(tunnel -> tunnel.getToClient().equals(clientId)).collect(Collectors.toList());
    }

    /**
     * 获取隧道
     *
     * @param
     */
    public static Collection<Tunnel> getTunnels() {
        return tunnelMap.values();
    }

    /**
     * 获取链路
     *
     * @param
     */
    public static Tunnel getTunnel(Integer toPort) {
        Collection<Tunnel> tunnels = tunnelMap.values();
        for (Tunnel tunnel : tunnels) {
            if (tunnel.getToClient().equals("server") && tunnel.getToPort().equals(toPort)) {
                return tunnel;
            }
        }
        return null;
    }

    /**
     * 更新隧道
     *
     * @param tunnel
     */
    public static void updateTunnelMap(Tunnel tunnel) {
        tunnelMap.put(tunnel.getId(), tunnel);
    }

    /**
     * 删除隧道
     *
     * @param tunnelId
     */
    public static void removeTunnelMap(String tunnelId) {
        tunnelMap.remove(tunnelId);
    }


}
